package com.minelx.scriptbuilder.script.attribute.value;

import com.minelx.scriptbuilder.script.IVariable;

public enum Operators {
	PLUS(Constants.PRIORITY_MEDIUM) {
		@Override
		public IAttribute calculate(IAttribute left, IAttribute right) {
			return Operator.plus(left, right);
		}
	},
	REDUCE(Constants.PRIORITY_MEDIUM) {
		@Override
		public IAttribute calculate(IAttribute left, IAttribute right) {
			return Operator.reduce(left, right);
		}
	},
	MULTI(Constants.PRIORITY_HIGH) {
		@Override
		public IAttribute calculate(IAttribute left, IAttribute right) {
			return Operator.multi(left, right);
		}
	},
	DIVIDE(Constants.PRIORITY_HIGH) {
		@Override
		public IAttribute calculate(IAttribute left, IAttribute right) {
			return Operator.divide(left, right);
		}
	},
	OR(Constants.PRIORITY_LOW) {
		@Override
		public IAttribute calculate(IAttribute left, IAttribute right) {
			return Operator.or(left, right);
		}
	},
	AND(Constants.PRIORITY_LOW) {
		@Override
		public IAttribute calculate(IAttribute left, IAttribute right) {
			return Operator.and(left, right);
		}
	}, UNKNOWN(Constants.PRIORITY_UNKNOWN) { // FIXME: 2021/3/18  Remove It ...
		@Override
		public IAttribute calculate(IAttribute left, IAttribute right) {
			return IAttribute.nil();
		}
	};

	private final int priority;

	Operators(int priority) {
		this.priority = priority;
	}

	public IVariable calculate(IVariable left, IVariable right) {
		return new IVariable() {
			@Override
			public IAttribute value() {
				return calculate(left.value(), right.value());
			}

			@Override
			public void assigned(IAttribute as) {
				throw new RuntimeException("operation failed.");
			}
		};
	}

	public abstract IAttribute calculate(IAttribute left, IAttribute right);

	public boolean biggerThan(Operators another) {
		return priority > another.priority;
	}

	public boolean equalsTo(Operators another) {
		return priority == another.priority;
	}

	public boolean lowerThan(Operators another) {
		return priority < another.priority;
	}

	public boolean bigOrEquals(Operators another) {
		return biggerThan(another) || equalsTo(another);
	}

	public boolean lowOrEquals(Operators another) {
		return lowerThan(another) || equalsTo(another);
	}

	public static Operators of(String operandAsText) {
		if (operandAsText.equals("+"))
			return PLUS;
		if (operandAsText.equals("-"))
			return REDUCE;
		if (operandAsText.equals("*"))
			return MULTI;
		if (operandAsText.equals("/"))
			return DIVIDE;
		if (operandAsText.equals("|"))
			return OR;
		if (operandAsText.equals("&"))
			return AND;
		throw new RuntimeException("unsupported operator: " + operandAsText);
	}

	private static class Constants {
		public static final int PRIORITY_UNKNOWN = 0;

		public static final int PRIORITY_LOW = 1;

		public static final int PRIORITY_MEDIUM = 2;

		public static final int PRIORITY_HIGH = 3;
	}
}
